package com.llkj.common.http;

import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.BiFunction;
import io.reactivex.functions.Function;
import timber.log.Timber;

/**
 * author: zhu.px
 * e-mail: 1271901673@qq.com
 * time  : 2018/4/25
 * desc  : 重试机制
 */
public class RetryWhenFun implements Function<Observable<? extends Throwable>, Observable<?>> {

    /**
     * 重试次数
     */
    private int count;

    /**
     * 延迟
     */
    private long delay;

    public RetryWhenFun(int count, long delay) {
        this.count = count;
        this.delay = delay;
    }

    private class Wrapper {
        private int index;
        private Throwable throwable;

        Wrapper(Throwable throwable, int index) {
            this.index = index;
            this.throwable = throwable;
        }
    }

    @Override
    public Observable<?> apply(@NonNull Observable<? extends Throwable> observable) {
        return observable.zipWith(Observable.range(1, count + 1), new BiFunction<Throwable, Integer, Wrapper>() {
            @Override
            public Wrapper apply(@NonNull Throwable throwable, @NonNull Integer integer) {
                return new Wrapper(throwable, integer);
            }
        }).flatMap(new Function<Wrapper, ObservableSource<?>>() {
            @Override
            public ObservableSource<?> apply(@NonNull Wrapper wrapper) {
                if ((wrapper.throwable instanceof ConnectException
                        || wrapper.throwable instanceof SocketTimeoutException
                        || wrapper.throwable instanceof TimeoutException)) {
                    if (wrapper.index < count + 1) {
                        return Observable.timer(delay, TimeUnit.MILLISECONDS);
                    }
                }
                return Observable.error(wrapper.throwable);
            }
        });
    }


}
